/**
 * Navit, a modular navigation system.
 * Copyright (C) 2005-2008 Navit Team
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 */

//TODO: get rid  from GList in module

#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include "config.h"
#include "debug.h"
#include "plugin.h"
#include "projection.h"
#include "item.h"
#include "map.h"
#include "maptype.h"
#include "attr.h"
#include "transform.h"
#include "file.h"
#include <dbus-1.0/dbus/dbus.h>
#include "traffic.h"
#include <json.h>
#include <dlfcn.h>

void
transformation_to_geo (struct coord_geo *g, struct coord *c)
{
	g->lng=c->x/6371000.0/M_PI*180;
	g->lat=navit_atan(exp(c->y/6371000.0))/M_PI*360-9;
}

static int map_id;

static void
map_destroy_traffic(struct map_priv *m)
{

	dbg(1,"map_destroy_traffic\n");
	if(m->charset) {
		g_free(m->charset);
	}
	if(m->library) {
		dlclose(m->library);
	}
	g_free(m);
}

static void
traffic_coord_rewind(void *priv_data)
{
}

//TODO: recode
static int
traffic_coord_get(void *priv_data, struct coord *c, int count)
{
	//dbg(0,"Count is %d\n",count);
	struct map_rect_priv *mr=priv_data;
	int ret=0;
	traffic_item *r = (traffic_item*)mr->traffic_list->prev->data;
	if(r){
		*c = r->coords[0];
		dbg (1,"%d -- %d \n", c[0].x,c[0].y);
		c++;
		*c = r->coords[1];
		ret=2;
	}
	return ret;
}

static void
traffic_attr_rewind(void *priv_data)
{
	struct map_rect_priv *mr=priv_data;
	mr->attr_pos=0;
	mr->attr_last=attr_none;
}


static int
traffic_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
{
//	struct map_rect_priv *mr=priv_data;
//	char *str=NULL;
	dbg(1,"not found\n");
	return 0;
}

static struct item_methods methods_traffic = {
        traffic_coord_rewind,
        traffic_coord_get,
        traffic_attr_rewind,
        traffic_attr_get,
};



static struct map_rect_priv *
map_rect_new_traffic(struct map_priv *map, struct map_selection *sel)
{
	struct map_rect_priv *mr;
	dbg(1,"map_rect_new_traffic\n");
	mr=g_new0(struct map_rect_priv, 1);
	mr->m=map;
	mr->sel=sel;
	if (map->flags & 1)
		mr->item.id_hi=1;
	else
		mr->item.id_hi=0;
	mr->item.id_lo=0;
	mr->item.meth=&methods_traffic;
	mr->item.priv_data=mr;
	mr->traffic_list=NULL;
	mr->sel = sel;

	query(mr);
	dbg (1,"0x%p\n",mr->traffic_list);
	return mr;
}




static void
map_rect_destroy_traffic(struct map_rect_priv *mr)
{
	if(mr) {
		if(mr->traffic_list){
			g_list_free (mr->traffic_list);
		}
		g_free(mr);
	}


}

static struct item *
map_rect_get_item_traffic(struct map_rect_priv *mr)
{
dbg(0,"Called!\n")
	if(mr->traffic_list && mr->traffic_list->next) {
		traffic_item *itm = mr->traffic_list->data;

		switch(itm->speed) {
		case 1:
			mr->item.type = item_from_name("street_traffic_red");
			break;
		case 2:
			mr->item.type = item_from_name("street_traffic_yellow");
			break;
		case 3:
			mr->item.type = item_from_name("street_traffic_green");
			break;
		}


		mr->traffic_list = g_list_next(mr->traffic_list);


		return &mr->item;
	}else {
		mr->traffic_list = g_list_first(mr->traffic_list);
		return NULL;
	}
		return &mr->item;
}

static struct item *
map_rect_get_item_byid_traffic(struct map_rect_priv *mr, int id_hi, int id_lo)
{
	return map_rect_get_item_traffic(mr);
}

static struct map_methods map_methods_traffic = {
	projection_mg,
	"iso8859-1",
	map_destroy_traffic,
	map_rect_new_traffic,
	map_rect_destroy_traffic,
	map_rect_get_item_traffic,
	map_rect_get_item_byid_traffic,
};



void* (*create_gp)(void);
void (*delete_gp)(void* gp);
int (*init_gp)(void* gp);
const char *(*get_data)(void* gp,double lu_lat, double lu_lng, double rb_lat, double rb_lng, int order);



// initializes new map instance and returns map methods struct to navit
static struct map_priv *
map_new_traffic(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl)
{
	struct map_priv *m;
	struct attr *data=attr_search(attrs, NULL, attr_data);
	struct attr *charset=attr_search(attrs, NULL, attr_charset);
	struct attr *flags=attr_search(attrs, NULL, attr_flags);
	char *error;
	if (! data)
		return NULL;
	dbg(1,"Map created !\n");
	*meth=map_methods_traffic;
	m=g_new0(struct map_priv, 1);
	m->id=++map_id;
	m->engine=g_strdup(data->u.str);
	if (flags)
		m->flags=flags->u.num; //
	m->library = dlopen("/home/hexlotar/cprojects/google_engine/Release/libgoogle_engine.so", RTLD_LAZY);
	if (!m->library)
	{
		dbg(0, "%s\n", dlerror());
	    return NULL;
	}

	create_gp = dlsym(m->library, "create_gp");
	if ((error = dlerror()) != NULL)
	{
		dbg(0, "%s\n", error);
	    return NULL;
	}
	delete_gp = dlsym(m->library, "delete_gp");
	if ((error = dlerror()) != NULL)
	{
		dbg(0, "%s\n", error);
	    return NULL;
	}
	init_gp = dlsym(m->library, "init_gp");
	if ((error = dlerror()) != NULL)
	{
		dbg(0, "%s\n", error);
	    return NULL;
	}
	get_data = dlsym(m->library, "get_data");
	if ((error = dlerror()) != NULL)
	{
		dbg(0, "%s\n", error);
	    return NULL;
	}




	if (charset) {
		m->charset=g_strdup(charset->u.str);
		meth->charset=m->charset;
	}
	return m;
}

// TODO: method to parse json string to list of traffic lines recode as allocator
// TODO: check data for correctness

struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error)
{
    struct json_tokener* tok;
    struct json_object* obj;

    tok = json_tokener_new();
    obj = json_tokener_parse_ex(tok, str, -1);
    *error = tok->err;
    if(tok->err != json_tokener_success) {
        obj = NULL;
    }

    json_tokener_free(tok);
    return obj;
}
int ParseJsonData (GList **TrafficList, char *strJson)
{

	int Length=0, i;
	struct json_object *JsonData;
	struct json_object *JsonTraffCoordData, *JsonTraffCoord, *JsonTmp;
	traffic_item *temp;
	struct coord_geo temp_coord;
	//dbg(0,"%s\n",strJson);

	if(strJson) {
		int error;

		JsonData = json_tokener_parse_verbose(strJson,&error);

		if(error==0) {

			JsonTraffCoordData = json_object_object_get(JsonData, "TraffData");
			Length = json_object_array_length(JsonTraffCoordData);
			for (i=0; i<Length; i++) {
				temp = (traffic_item*)g_malloc(sizeof(traffic_item));
				JsonTraffCoord = json_object_array_get_idx(JsonTraffCoordData, i);
				JsonTmp = json_object_object_get(JsonTraffCoord, "lat1");
				temp_coord.lat =  json_object_get_double(JsonTmp);
				//printf("%f\n",temp_coord.lat);
				JsonTmp = json_object_object_get(JsonTraffCoord, "lng1");
				temp_coord.lng = json_object_get_double(JsonTmp);
				transform_from_geo(projection_mg,&temp_coord,&temp->coords[0]);
				dbg(0,"ALLL OK4!\n");
				JsonTmp = json_object_object_get(JsonTraffCoord, "lat2");
				temp_coord.lat =  json_object_get_double(JsonTmp);
				JsonTmp = json_object_object_get(JsonTraffCoord, "lng2");
				temp_coord.lng = json_object_get_double(JsonTmp);
				transform_from_geo(projection_mg,&temp_coord,&temp->coords[1]);
				JsonTmp = json_object_object_get(JsonTraffCoord, "speed");
				temp->speed = (char)json_object_get_int(JsonTmp);
				//dbg (0,"list0x%x\n",*TrafficList);
				*TrafficList = g_list_append(*TrafficList,temp);

			}
			temp = (traffic_item*)g_malloc(sizeof(traffic_item));
			*TrafficList = g_list_append(*TrafficList,temp);
		}
	}

	return Length;
}

#define dCALLER "traffic.method.caller"
#define dOBJECT "/traffic/method/Object"
#define dSERVER "traffic.method.server"
#define dTYPE "traffic.method.Type"



void write_log(char *str_log)  {
	FILE *fp = fopen("LOG.TXT","w+");
	if(fp) {
		fprintf(fp,"%s",str_log);
	}
	fclose(fp);
}
// function to query over dbus

void query(struct map_rect_priv *mr)
{
	//char *jsonString;/*="{\
\"TraffData\": [\
        {\
          \"lat1\" : 40.7406,\
          \"lng1\" : -73.9902,\
           \"lat2\" :40.7406,\
           \"lng2\" :-73.9902,\
           \"speed\" : 5\
        },\
        {\
          \"lat1\" : 40.7406,\
          \"lng1\" : -73.9902,\
           \"lat2\" :40.7405,\
           \"lng2\" :-73.99,\
           \"speed\" : 5\
        },\
        {\
          \"lat1\" : 40.7405,\
          \"lng1\" : -73.99,\
           \"lat2\" :40.7406,\
           \"lng2\" :-73.99,\
           \"speed\" : 5\
        }]}\
";*/

	char param[256];
	struct coord_geo geo1,geo2;
	transform_to_geo(projection_mg,&mr->sel->u.c_rect.lu,&geo1);
	transform_to_geo(projection_mg,&mr->sel->u.c_rect.rl,&geo2);
	sprintf(param,"get lp: %lf %lf rb: %lf %lf order:%d",geo1.lat,geo1.lng,geo2.lat,geo2.lng,mr->sel->order);
	dbg(0,"%s\n",param);
	char *param1 = "get";
	mr->provider = create_gp();
	init_gp(mr->provider);
	//const char *jsonString = get_data(mr->provider,51.0, 30.0, 50.0, 31.0, 12);
	const char *jsonString = get_data(mr->provider,geo1.lat,geo1.lng,geo2.lat,geo2.lng,mr->sel->order-1);
	//const char *jsonString = NULL;
	
	//dbus_query(param1,&jsonString);

	printf("Value: %s\n",jsonString);
	if(jsonString!=NULL) {
		write_log(jsonString);
		ParseJsonData(&mr->traffic_list,jsonString);
	}
	delete_gp(mr->provider);
}

void
plugin_init(void)
{
	dbg(1,"traffic: plugin_init\n");
	plugin_register_map_type("traffic", map_new_traffic);
}
